/*
 * Copyright (C) 2007-2012 Geometer Plus <contact@geometerplus.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 */

package org.geometerplus.zlibrary.core.filesystem;


import com.example.administrator.fangbook.dataLibrary.book.ShelfItemBook;

import org.geometerplus.fbreader.filetype.FileType17KTxtNovel;
import org.geometerplus.fbreader.filetype.FileTypeTxt;
import org.geometerplus.zlibrary.core.drm.EncryptionMethod;
import org.geometerplus.zlibrary.core.drm.FileEncryptionInfo;
import org.geometerplus.zlibrary.core.drm.embedding.EmbeddingInputStream;
import org.geometerplus.zlibrary.core.util.InputStreamHolder;
import org.geometerplus.zlibrary.text.view.ZLTextPosition;

import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

/**
 * @author enjoy
 */
public abstract class ZLFile implements ZLFileInter, InputStreamHolder, Serializable {

    private final static HashMap<String, ZLFile> ourCachedFiles = new HashMap<String, ZLFile>();
    /**
     * 扩展名
     */
    private String myExtension;
    /**
     * 当前书籍
     */
    private ShelfItemBook mShelfBook;
    /**
     * 书籍开始的位置记录
     */
    private ZLTextPosition mStartPositioin;

    private String myShortName;

    protected int myArchiveType;

    private boolean myIsCached;

    protected void init() {
        final String name = getLongName();
        final int index = name.lastIndexOf('.');
        myExtension = (index > 0) ? name.substring(index + 1).toLowerCase().intern() : "";
        myShortName = name.substring(name.lastIndexOf('/') + 1);

        int archiveType = ArchiveType.NONE;
        if (myExtension == "zip") {
            archiveType |= ArchiveType.ZIP;
        } else if (myExtension == "oebzip") {
            archiveType |= ArchiveType.ZIP;
        } else if (myExtension == "epub") {
            archiveType |= ArchiveType.ZIP;
        } else if (myExtension == "tar") {
            archiveType |= ArchiveType.TAR;
        }
        myArchiveType = archiveType;
    }

    public static ZLFile createFile(ZLFile parent, String name) {
        ZLFile file = null;
        if (parent == null) {
            ZLFile cached = ourCachedFiles.get(name);
            if (cached != null) {
                return cached;
            }
            if (!name.startsWith("/")) {
                return ZLResourceFile.createResourceFile(name);
            } else {
                return new ZLPhysicalFile(name);
            }
        } else if ((parent instanceof ZLPhysicalFile) && (parent.getParent() == null)) {
            file = new ZLPhysicalFile(parent.getPath() + '/' + name);
        } else if (parent instanceof ZLResourceFile) {
            file = ZLResourceFile.createResourceFile((ZLResourceFile) parent, name);
        } else {
            file = ZLArchiveEntryFile.createArchiveEntryFile(parent, name);
        }

        if (!ourCachedFiles.isEmpty() && (file != null)) {
            ZLFile cached = ourCachedFiles.get(file.getPath());
            if (cached != null) {
                return cached;
            }
        }
        return file;
    }

    public static ZLFile createFileByUri(String uri) {
        if (uri == null) {
            return null;
        }
        if (uri.startsWith(FileType17KTxtNovel.FileMode)) {
            return ZL17KPlainTxtFile.createByUri(uri);
        }
        if (uri.startsWith(FileTypeTxt.FileMode)) {
            return ZLTxtFile.createByUri(uri);
        }
        return createFileByPath(uri);
    }

    public static ZLFile createFileByPath(String path) {
        if (path == null) {
            return null;
        }
        ZLFile cached = ourCachedFiles.get(path);
        if (cached != null) {
            return cached;
        }

        if (path.toLowerCase().startsWith(FileType17KTxtNovel.FileMode)) {

            return ZL17KPlainTxtFile.createFileByPath(path);
        }
        if (path.toLowerCase().startsWith(FileTypeTxt.FileMode)) {

            return ZLTxtFile.createFileByPath(path);
        }
        if (!path.startsWith("/")) {
            return ZLResourceFile.createResourceFile(path);
        }
        int index = path.lastIndexOf(':');
        if (index > 1) {
            return ZLArchiveEntryFile.createArchiveEntryFile(
                    createFileByPath(path.substring(0, index)), path.substring(index + 1)
            );
        }
        return new ZLPhysicalFile(path);
    }

    public abstract long size();

    public abstract boolean exists();

    public abstract boolean isDirectory();

    /**
     * 得到路径
     *
     * @return
     */
    public abstract String getPath();

    /**
     * 得到父文件
     *
     * @return
     */
    public abstract ZLFile getParent();

    /**
     * 得到物理文件
     *
     * @return
     */
    public abstract ZLPhysicalFile getPhysicalFile();

    /**
     * 得到文件流
     *
     * @return
     * @throws IOException
     */
    public abstract InputStream getInputStream() throws IOException;


    /**
     * 根据FileEncryptionInfo（加密文件）得到文件流
     *
     * @param encryptionInfo
     * @return
     * @throws IOException
     */
    public final InputStream getInputStream(FileEncryptionInfo encryptionInfo) throws IOException {
        if (encryptionInfo == null) {
            return getInputStream();
        }

        if (EncryptionMethod.EMBEDDING.equals(encryptionInfo.Method)) {
            return new EmbeddingInputStream(getInputStream(), encryptionInfo.ContentId);
        }

        throw new IOException("Encryption method " + encryptionInfo.Method + " is not supported");
    }


    public final boolean isArchive() {
        return (0 != (myArchiveType & ArchiveType.ARCHIVE));
    }

    public abstract String getLongName();

    public String getShortName() {
        return myShortName;
    }

    public final String getExtension() {
        return myExtension;
    }

    public void setExtension(String strExtension) {
        myExtension = strExtension;
    }

    /**
     * @return 返回一个可序列话的空集合
     */
    protected List<ZLFile> directoryEntries() {
        return Collections.emptyList();
    }

    /**
     * 得到当前文件的孩子们
     *
     * @return
     */
    public final List<ZLFile> children() {
        if (exists()) {
            //当前文件存在
            if (isDirectory()) {
                //是目录，返回一个空集合
                return directoryEntries();
            } else if (isArchive()) {
                return ZLArchiveEntryFile.archiveEntries(this);
            }
        }
        //当前文件不存在返回要给空集合
        return Collections.emptyList();
    }

    @Override
    public int hashCode() {
        return getPath().hashCode();
    }

    @Override
    public boolean equals(Object o) {
        if (o == this) {
            return true;
        }
        if (!(o instanceof ZLFile)) {
            return false;
        }
        return getPath().equals(((ZLFile) o).getPath());
    }

    protected boolean isCached() {
        return myIsCached;
    }

    public void setCached(boolean cached) {
        myIsCached = cached;
        if (cached) {
            ourCachedFiles.put(getPath(), this);
        } else {
            ourCachedFiles.remove(getPath());
            if (0 != (myArchiveType & ArchiveType.ZIP)) {
                ZLZipEntryFile.removeFromCache(this);
            }
        }
    }


    public ShelfItemBook getShelfBook() {
        return mShelfBook;
    }

    public void setShelfBook(ShelfItemBook book) {
        mShelfBook = book;
    }

    /**
     * @return the startPositioin
     */
    public ZLTextPosition getStartPositioin() {
        return mStartPositioin;
    }

    public void setStartPositioin(ZLTextPosition startPositioin) {
        mStartPositioin = startPositioin;
    }

    /**
     * 获取当前阅读的图书名称
     *
     * @return
     */
    @Override
    public String getBookName() {
        return mShelfBook.getName();
    }

    /**
     * 当前阅读的章节名称
     *
     * @return
     */
    @Override
    public String getChapterName() {
        return "";
    }

    public String getFileMode() {
        return "";
    }

    public String getUri() {
        return getFileMode() + getPath();
    }

    @Override
    public String getBookId() {
        return null;
    }

    @Override
    public String getChapterId() {
        return null;
    }


    /**
     * 档案类型
     */
    protected interface ArchiveType {
        int NONE = 0;
        int GZIP = 0x0001;
        int BZIP2 = 0x0002;
        int COMPRESSED = 0x00ff;
        int ZIP = 0x0100;
        int TAR = 0x0200;
        int ARCHIVE = 0xff00;
    }
}
